# -*- coding: utf-8 -*-
"""模板参数系统测试"""

from mcpy.template_param import TemplateParam, ConstraintKind
from mcpy.builtin.builtin_table import parse_type_vars
from mcpy.symbol_meta import Signature, TypeInfo, TypeKind, Symbol, SymbolKind
from mcpy.type_system import parse_type_with_context
from mcpy.symbol_registry import SymbolRegistry, get_global_registry
from mcpy.type_inference import TypeInferenceEngine
from mcpy.builtin.builtin_table import load_builtin_signatures
from mcpy.ir.declarations.typevar import IRTypeVar
from mcpy.type_system import is_protocol_implementation


def test_create_unconstrained_param():
    """测试创建无约束的模板参数"""
    param = TemplateParam(name="T", description="通用类型")
    assert param.name == "T"
    assert param.constraint_kind == ConstraintKind.NONE
    assert not param.has_constraint()


def test_create_union_param():
    """测试创建 union 约束的模板参数"""
    param = TemplateParam(
        name="T_numeric",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int", "float"],
    )
    assert param.name == "T_numeric"
    assert param.constraint_kind == ConstraintKind.UNION
    assert param.has_constraint()
    assert "int" in param.allowed_types
    assert "float" in param.allowed_types


def test_from_type_var_config_unconstrained():
    """测试从配置创建无约束参数"""
    config = {"description": "通用类型"}
    param = TemplateParam.from_type_var_config("T", config)
    assert param.name == "T"
    assert param.constraint_kind == ConstraintKind.NONE
    assert param.description == "通用类型"


def test_from_type_var_config_with_constraints():
    """测试从配置创建有约束参数"""
    config = {"description": "数值类型", "constraints": ["int", "float"]}
    param = TemplateParam.from_type_var_config("T_numeric", config)
    assert param.name == "T_numeric"
    assert param.constraint_kind == ConstraintKind.UNION
    assert param.allowed_types == ["int", "float"]
    assert param.description == "数值类型"


def test_parse_empty_type_vars():
    """测试解析空的 TYPE_VARS"""
    result = parse_type_vars({})
    assert result == {}


def test_parse_multiple_type_vars():
    """测试解析多个 TYPE_VARS"""
    type_vars = {
        "T": {"description": "通用类型"},
        "T_numeric": {
            "description": "数值类型",
            "constraints": ["int", "float"],
        },  # 使用 constraints
        "K": {"description": "键类型"},
        "V": {"description": "值类型"},
    }
    result = parse_type_vars(type_vars)

    assert len(result) == 4
    assert "T" in result
    assert "T_numeric" in result
    assert "K" in result
    assert "V" in result

    # 验证 T
    assert result["T"].name == "T"
    assert result["T"].constraint_kind == ConstraintKind.NONE

    # 验证 T_numeric（这里使用 constraints，所以是 UNION）
    assert result["T_numeric"].name == "T_numeric"
    assert result["T_numeric"].constraint_kind == ConstraintKind.UNION
    # 使用 constraints 时是具体类型列表
    assert "int" in result["T_numeric"].allowed_types
    assert "float" in result["T_numeric"].allowed_types


def _create_test_signature(template_params_detailed):
    """创建测试用的 Signature（不依赖 builtin 加载）"""
    return Signature(
        function_name="test_func",
        param_types=["T_numeric"],
        return_type="T_numeric",
        template_params=["T_numeric"],
        template_params_detailed=template_params_detailed,
        template_inference_map={"T_numeric": [0]},
    )


def test_unconstrained_template_matching():
    """测试无约束模板参数匹配"""
    # 创建无约束模板参数
    t_param = TemplateParam(name="T")
    sig = _create_test_signature([t_param])

    # 任何类型都应该匹配
    int_type = TypeInfo(kind=TypeKind.CLASS, name="int")
    str_type = TypeInfo(kind=TypeKind.CLASS, name="str")

    score_int = sig._get_template_match_score("T", int_type)
    score_str = sig._get_template_match_score("T", str_type)

    assert score_int == 50  # 通用模板匹配
    assert score_str == 50


def test_union_constraint_matching():
    """测试 union 约束匹配"""
    # 创建数值类型约束
    t_numeric = TemplateParam(
        name="T_numeric",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int", "float"],
    )
    sig = _create_test_signature([t_numeric])

    # 创建类型信息
    int_type = TypeInfo(kind=TypeKind.CLASS, name="int")
    float_type = TypeInfo(kind=TypeKind.CLASS, name="float")
    str_type = TypeInfo(kind=TypeKind.CLASS, name="str")

    # int 和 float 应该匹配
    score_int = sig._get_template_match_score("T_numeric", int_type)
    score_float = sig._get_template_match_score("T_numeric", float_type)
    score_str = sig._get_template_match_score("T_numeric", str_type)

    assert score_int == 100  # 精确约束匹配
    assert score_float == 100
    assert score_str == 0  # 不满足约束


def test_signature_call_matching_with_constraints():
    """测试带约束的签名调用匹配"""
    # 创建数值类型约束
    t_numeric = TemplateParam(
        name="T_numeric",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int", "float"],
    )
    sig = Signature(
        function_name="abs",
        param_types=["T_numeric"],
        return_type="T_numeric",
        template_params=["T_numeric"],
        template_params_detailed=[t_numeric],
        template_inference_map={"T_numeric": [0]},
    )

    # 创建类型信息
    int_type = TypeInfo(kind=TypeKind.CLASS, name="int")
    float_type = TypeInfo(kind=TypeKind.CLASS, name="float")
    str_type = TypeInfo(kind=TypeKind.CLASS, name="str")

    # 测试调用匹配
    score_int = sig.matches_call_with_typeinfo("abs", [int_type])
    score_float = sig.matches_call_with_typeinfo("abs", [float_type])
    score_str = sig.matches_call_with_typeinfo("abs", [str_type])

    assert score_int > 0, "abs(int) should match"
    assert score_float > 0, "abs(float) should match"
    assert score_str == 0, "abs(str) should not match"

    # 有约束的匹配分数应该高于基础分数
    assert score_int >= 90, f"Expected score >= 90, got {score_int}"
    assert score_float >= 90, f"Expected score >= 90, got {score_float}"


def test_inference_map_construction():
    """测试推导映射的构建"""
    # 创建一个有两个参数的签名，T 可以从两个参数推导
    t_param = TemplateParam(name="T")
    sig = Signature(
        function_name="max",
        param_types=["T", "T"],
        return_type="T",
        template_params=["T"],
        template_params_detailed=[t_param],
        template_inference_map={"T": [0, 1]},  # T 可以从参数 0 和 1 推导
    )

    # 验证推导映射
    assert "T" in sig.template_inference_map
    assert 0 in sig.template_inference_map["T"]
    assert 1 in sig.template_inference_map["T"]


def test_multiple_template_params_inference():
    """测试多个模板参数的推导"""
    # 创建 dict[K, V] 类型的签名
    k_param = TemplateParam(name="K")
    v_param = TemplateParam(name="V")

    sig = Signature(
        function_name="dict_get",
        param_types=["dict[K, V]", "K"],
        return_type="V",
        template_params=["K", "V"],
        template_params_detailed=[k_param, v_param],
        template_inference_map={
            "K": [0, 1],  # K 可以从参数 0（dict的键）和参数 1 推导
            "V": [0],  # V 只能从参数 0（dict的值）推导
        },
    )

    # 验证推导映射
    assert "K" in sig.template_inference_map
    assert "V" in sig.template_inference_map
    assert 0 in sig.template_inference_map["K"]
    assert 1 in sig.template_inference_map["K"]
    assert 0 in sig.template_inference_map["V"]


def test_builtin_signatures_have_template_params():
    """测试 builtin 签名包含模板参数信息"""
    signatures = load_builtin_signatures()

    # 查找有模板参数的签名
    template_sigs = [
        sig
        for sig in signatures
        if sig.template_params_detailed is not None
        and len(sig.template_params_detailed) > 0
    ]

    # 应该有一些带模板参数的签名
    assert (
        len(template_sigs) > 0
    ), "Should have some signatures with template parameters"


def test_abs_function_signature_structure():
    """测试 abs 函数签名的结构（不测试具体的约束内容）"""
    signatures = load_builtin_signatures()

    # 查找 abs 函数的签名
    abs_signatures = [sig for sig in signatures if sig.function_name == "abs"]
    assert len(abs_signatures) > 0, "Should have abs function signatures"

    abs_sig = abs_signatures[0]

    # 验证签名结构（不关心具体约束）
    # 如果有 template_params_detailed，验证它是 TemplateParam 列表
    if abs_sig.template_params_detailed:
        assert isinstance(abs_sig.template_params_detailed, list)
        for param in abs_sig.template_params_detailed:
            assert isinstance(param, TemplateParam)
            assert param.name  # 应该有名称

    # 验证向后兼容性：仍然有旧字段
    assert abs_sig.template_params is not None


def test_signature_has_both_old_and_new_fields():
    """测试 Signature 同时有旧字段和新字段"""
    t_numeric = TemplateParam(
        name="T_numeric",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int", "float"],
    )

    sig = Signature(
        function_name="test",
        param_types=["T_numeric"],
        return_type="T_numeric",
        template_params=["T_numeric"],  # 旧字段
        template_params_detailed=[t_numeric],  # 新字段
    )

    # 验证两个字段都存在
    assert sig.template_params == ["T_numeric"]
    assert sig.template_params_detailed
    assert len(sig.template_params_detailed) == 1
    assert sig.template_params_detailed[0].name == "T_numeric"


def test_old_type_vars_field_still_works():
    """测试旧的 type_vars 字段仍然工作"""
    sig = Signature(
        function_name="test",
        param_types=["T_numeric"],
        return_type="T_numeric",
        template_params=["T_numeric"],
        type_vars={"T_numeric": {"constraints": ["int", "float"]}},  # 旧字段
    )

    # 旧的匹配逻辑应该仍然工作
    int_type = TypeInfo(kind=TypeKind.CLASS, name="int")
    str_type = TypeInfo(kind=TypeKind.CLASS, name="str")

    score_int = sig._get_template_match_score("T_numeric", int_type)
    score_str = sig._get_template_match_score("T_numeric", str_type)

    assert score_int == 100  # 应该匹配
    assert score_str == 0  # 不应该匹配


def test_unconstrained_typevar():
    """测试无约束的 TypeVar"""
    # T = TypeVar("T")
    typevar = IRTypeVar(name="T")
    template_param = typevar.to_template_param()

    assert template_param.name == "T"
    assert template_param.constraint_kind == ConstraintKind.NONE
    assert not template_param.has_constraint()


def test_constrained_typevar():
    """测试有约束的 TypeVar"""
    # T_numeric = TypeVar("T_numeric", int, float)
    typevar = IRTypeVar(name="T_numeric", constraints=["int", "float"])
    template_param = typevar.to_template_param()

    assert template_param.name == "T_numeric"
    assert template_param.constraint_kind == ConstraintKind.UNION
    assert template_param.has_constraint()
    assert "int" in template_param.allowed_types
    assert "float" in template_param.allowed_types


def test_bound_typevar():
    """测试有 bound 的 TypeVar"""
    # T_comparable = TypeVar("T_comparable", bound="Comparable")
    typevar = IRTypeVar(name="T_comparable", bound="Comparable")
    template_param = typevar.to_template_param()

    assert template_param.name == "T_comparable"
    assert template_param.constraint_kind == ConstraintKind.NONE
    assert "bound=Comparable" in template_param.description


class TestTypeVarSymbolLookup:
    """测试 TypeVar 符号查找（来自 test_typevar_lookup.py）"""

    def setup_method(self):
        """设置测试环境"""
        self.registry = get_global_registry()

    def test_builtin_typevar_symbol_exists(self):
        """测试 builtin TypeVar 符号存在"""
        # 查找 T_numeric TypeVar
        symbol = self.registry.get_symbol("T_numeric")

        assert symbol is not None, "T_numeric 符号应该存在"
        assert symbol.name == "T_numeric"

    def test_typevar_is_type_param(self):
        """测试 TypeVar 是类型参数符号"""

        symbol = self.registry.get_symbol("T_numeric")

        assert symbol is not None
        assert symbol.kind == SymbolKind.TYPE_PARAM

    def test_typevar_type_is_type_param(self):
        """测试 TypeVar 的类型是 TYPE_PARAM"""
        symbol = self.registry.get_symbol("T_numeric")

        assert symbol is not None
        assert symbol.type_info is not None
        assert symbol.type_info.kind == TypeKind.TYPE_PARAM

    def test_typevar_has_template_params(self):
        """测试 TypeVar 包含约束信息"""
        symbol = self.registry.get_symbol("T_numeric")

        assert symbol is not None
        assert symbol.template_params is not None
        assert len(symbol.template_params) > 0

        # 获取约束信息
        template_param = symbol.template_params[0]
        assert template_param.name == "T_numeric"

        # bound 在创建时保存，但延迟解析
        assert template_param.bound == "Number"

        # 触发延迟解析
        dummy_type = TypeInfo(name="int", kind=TypeKind.PRIMITIVE)
        template_param.matches_type(dummy_type)

        # 解析后应该是 PROTOCOL
        assert template_param.constraint_kind == ConstraintKind.PROTOCOL

        # Number 协议要求实现算术和比较方法
        assert len(template_param.required_methods) > 0
        assert "__add__" in template_param.required_methods

    def test_typevar_stored_in_types(self):
        """测试 TypeVar 存储在 _types 中"""
        # 直接访问内部存储
        assert "T_numeric" in self.registry._types

        symbol = self.registry._types["T_numeric"]
        assert symbol.kind == SymbolKind.TYPE_PARAM
        assert symbol.type_info
        assert symbol.type_info.kind == TypeKind.TYPE_PARAM

    def test_typevar_not_in_functions(self):
        """测试 TypeVar 不在 _functions 中"""
        # TypeVar 应该不在函数表中
        assert "T_numeric" not in self.registry._functions


def test_template_param_bound_resolution():
    """测试模板参数 bound 延迟解析

    bound 在创建时不立即解析（避免循环依赖），而是在首次使用时延迟解析。
    """
    # bound 引用 Protocol
    config = {
        "description": "整数类型",
        "bound": "Integer",
    }
    param = TemplateParam.from_type_var_config("T_int", config)

    # 创建时保存 bound 名称，但未解析
    assert param.bound == "Integer"
    assert param.constraint_kind == ConstraintKind.NONE  # 延迟解析前为 NONE

    # 触发延迟解析（通过调用 matches_type）
    int_type = TypeInfo(name="int", kind=TypeKind.PRIMITIVE)
    result = param.matches_type(int_type)

    # 解析后应该变为 PROTOCOL 约束
    assert param.constraint_kind == ConstraintKind.PROTOCOL
    assert len(param.required_methods) > 0
    assert "__add__" in param.required_methods
    assert "__mul__" in param.required_methods
    assert result is True  # int 满足 Integer 协议


def test_protocol_type_matching():
    """测试 Protocol 类型匹配逻辑"""
    # 创建 Integer Protocol 参数
    config = {
        "bound": "Integer",
    }
    param = TemplateParam.from_type_var_config("T_int", config)

    # int 类型通过 builtin map 匹配（实际匹配在 _check_protocol_constraint 中）
    int_type = TypeInfo(name="int", kind=TypeKind.PRIMITIVE)
    # int 在 _get_builtin_methods_map 中定义，应该匹配
    result = param.matches_type(int_type)
    assert result is True, "int 应该满足 Integer 协议"

    # 验证延迟解析后的约束类型
    assert param.constraint_kind == ConstraintKind.PROTOCOL


def test_comparable_vs_iterable():
    """测试不同 Protocol 的区分"""
    # Comparable 协议
    comparable = TemplateParam.from_type_var_config(
        "T_comparable", {"bound": "Comparable"}
    )

    # Iterable 协议
    iterable = TemplateParam.from_type_var_config("T_iterable", {"bound": "Iterable"})

    # 触发延迟解析
    dummy_type = TypeInfo(name="int", kind=TypeKind.PRIMITIVE)
    comparable.matches_type(dummy_type)
    iterable.matches_type(dummy_type)

    # 方法应该不同
    assert set(comparable.required_methods) != set(iterable.required_methods)
    assert "__lt__" in comparable.required_methods
    assert "__iter__" in iterable.required_methods


def test_mixed_constraints():
    """测试混合约束（constraints + bound）"""
    # 只有 constraints（具体类型）
    param1 = TemplateParam.from_type_var_config("T_float", {"constraints": ["float"]})
    assert param1.constraint_kind == ConstraintKind.UNION

    # 只有 bound（Protocol）- 需要触发延迟解析
    param2 = TemplateParam.from_type_var_config("T_numeric", {"bound": "Number"})
    # 触发延迟解析
    dummy_type = TypeInfo(name="int", kind=TypeKind.PRIMITIVE)
    param2.matches_type(dummy_type)
    assert param2.constraint_kind == ConstraintKind.PROTOCOL

    # bound 优先于 constraints
    param3 = TemplateParam.from_type_var_config(
        "T_test", {"bound": "Integer", "constraints": ["str"]}
    )
    # 触发延迟解析
    param3.matches_type(dummy_type)
    assert param3.constraint_kind == ConstraintKind.PROTOCOL
    assert "__add__" in param3.required_methods


class TestProtocolTemplateMatching:
    """测试 Protocol 模板参数提取

    测试 Iterable[T_comparable] 匹配 set[int] 这样的场景
    """

    def setup_method(self):
        """设置测试环境"""
        self.engine = TypeInferenceEngine()

    def test_iterable_protocol_matches_list(self):
        """测试 Iterable 协议匹配 list 类型"""
        protocol_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="Iterable",
            args=[TypeInfo(TypeKind.TEMPLATE, "T_comparable")],
        )
        actual_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="list",
            args=[TypeInfo(TypeKind.PRIMITIVE, "int")],
        )

        assert is_protocol_implementation(protocol_type, actual_type)

    def test_iterable_protocol_matches_set(self):
        """测试 Iterable 协议匹配 set 类型"""
        protocol_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="Iterable",
            args=[TypeInfo(TypeKind.TEMPLATE, "T_comparable")],
        )
        actual_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="set",
            args=[TypeInfo(TypeKind.PRIMITIVE, "int")],
        )

        assert is_protocol_implementation(protocol_type, actual_type)

    def test_extract_template_params_from_iterable(self):
        """测试从 Iterable[T_comparable] 提取模板参数"""
        # Protocol 类型：Iterable[T_comparable]
        protocol_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="Iterable",
            args=[TypeInfo(TypeKind.TEMPLATE, "T_comparable")],
        )
        # 实际类型：set[int]
        actual_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="set",
            args=[TypeInfo(TypeKind.PRIMITIVE, "int")],
        )

        template_values = {}
        self.engine._match_and_extract_template_params(
            protocol_type, actual_type, template_values
        )

        # 应该提取出 T_comparable = int
        assert "T_comparable" in template_values
        assert template_values["T_comparable"].name == "int"
        assert template_values["T_comparable"].kind == TypeKind.PRIMITIVE

    def test_extract_template_params_from_list(self):
        """测试从 list[int] 提取模板参数"""
        # Protocol 类型：Iterable[T_comparable]
        protocol_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="Iterable",
            args=[TypeInfo(TypeKind.TEMPLATE, "T_comparable")],
        )
        # 实际类型：list[int]
        actual_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="list",
            args=[TypeInfo(TypeKind.PRIMITIVE, "int")],
        )

        template_values = {}
        self.engine._match_and_extract_template_params(
            protocol_type, actual_type, template_values
        )

        # 应该提取出 T_comparable = int
        assert "T_comparable" in template_values
        assert template_values["T_comparable"].name == "int"

    def test_extract_template_params_from_float_set(self):
        """测试从 set[float] 提取模板参数"""
        protocol_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="Iterable",
            args=[TypeInfo(TypeKind.TEMPLATE, "T_comparable")],
        )
        actual_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="set",
            args=[TypeInfo(TypeKind.PRIMITIVE, "float")],
        )

        template_values = {}
        self.engine._match_and_extract_template_params(
            protocol_type, actual_type, template_values
        )

        # 应该提取出 T_comparable = float
        assert "T_comparable" in template_values
        assert template_values["T_comparable"].name == "float"

    def test_non_protocol_type_does_not_match(self):
        """测试非 Protocol 类型不匹配"""
        protocol_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="SomeOtherType",
            args=[TypeInfo(TypeKind.TEMPLATE, "T")],
        )
        actual_type = TypeInfo(
            kind=TypeKind.GENERIC,
            name="set",
            args=[TypeInfo(TypeKind.PRIMITIVE, "int")],
        )
        assert not is_protocol_implementation(protocol_type, actual_type)


def test_parse_primitive_type_without_context():
    """测试解析基础类型（无上下文）"""
    type_info = parse_type_with_context("int")
    assert type_info.kind == TypeKind.PRIMITIVE
    assert type_info.name == "int"


def test_parse_generic_type_without_context():
    """测试解析泛型类型（无上下文）"""
    type_info = parse_type_with_context("list[int]")
    assert type_info.kind == TypeKind.GENERIC
    assert type_info.name == "list"
    assert len(type_info.args) == 1
    assert type_info.args[0].name == "int"


def test_parse_typevar_without_context_fallback_to_primitive():
    """测试解析未注册的类型（无上下文时回退到 PRIMITIVE）"""
    # 使用一个肯定不存在的类型名
    type_info = parse_type_with_context("UnknownType_XYZ_123")
    assert type_info.kind == TypeKind.PRIMITIVE
    assert type_info.name == "UnknownType_XYZ_123"


def test_builtin_typevar_recognized_globally():
    """测试内置 TypeVar 能被全局识别"""
    # T 是内置的 TypeVar，即使没有提供上下文也应该被识别
    type_info = parse_type_with_context("T")
    assert type_info.kind == TypeKind.TYPE_PARAM
    assert type_info.name == "T"


def test_parse_typevar_with_global_registry():
    """测试解析 TypeVar（使用全局注册表）"""
    # 全局注册表中应该已经注册了内置的 TypeVar（如 T）
    global_registry = get_global_registry()

    # 注册一个测试用的 TypeVar
    template_param = TemplateParam(
        name="T_test",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int"],
        description="测试用 TypeVar",
    )
    typevar_symbol = Symbol(
        name="T_test",
        kind=SymbolKind.TYPE_PARAM,
        type_info=TypeInfo(
            kind=TypeKind.TYPE_PARAM,
            name="T_test",
            template_constraints=["int"],
        ),
        template_params=[template_param],
        module="test",
    )
    global_registry._types["T_test"] = typevar_symbol

    # 使用新函数解析，应该能识别为 TYPE_PARAM
    type_info = parse_type_with_context("T_test")
    assert type_info.kind == TypeKind.TYPE_PARAM
    assert type_info.name == "T_test"
    assert type_info.template_constraints == ["int"]


def test_parse_typevar_with_custom_registry():
    """测试解析 TypeVar（使用自定义注册表）"""
    # 创建自定义注册表
    registry = SymbolRegistry()

    # 注册一个带约束的 TypeVar
    template_param = TemplateParam(
        name="T_custom",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int", "str", "bool"],
        description="自定义 TypeVar，约束为 int | str | bool",
    )
    typevar_symbol = Symbol(
        name="T_custom",
        kind=SymbolKind.TYPE_PARAM,
        type_info=TypeInfo(
            kind=TypeKind.TYPE_PARAM,
            name="T_custom",
            template_constraints=["int", "str", "bool"],
        ),
        template_params=[template_param],
        module="custom",
    )
    registry._types["T_custom"] = typevar_symbol

    # 使用新函数解析，传入 registry
    type_info = parse_type_with_context("T_custom", registry=registry)
    assert type_info.kind == TypeKind.TYPE_PARAM
    assert type_info.name == "T_custom"
    assert type_info.template_constraints == ["int", "str", "bool"]


def test_parse_generic_with_typevar():
    """测试解析包含 TypeVar 的泛型类型"""
    # 创建注册表并注册 TypeVar
    registry = SymbolRegistry()

    template_param = TemplateParam(
        name="T",
        constraint_kind=ConstraintKind.NONE,
        description="无约束 TypeVar",
    )
    typevar_symbol = Symbol(
        name="T",
        kind=SymbolKind.TYPE_PARAM,
        type_info=TypeInfo(kind=TypeKind.TYPE_PARAM, name="T"),
        template_params=[template_param],
        module="test",
    )
    registry._types["T"] = typevar_symbol

    # 解析 list[T]
    type_info = parse_type_with_context("list[T]", registry=registry)
    assert type_info.kind == TypeKind.GENERIC
    assert type_info.name == "list"
    assert len(type_info.args) == 1
    # 关键：泛型参数中的 T 应该被识别为 TYPE_PARAM
    assert type_info.args[0].kind == TypeKind.TYPE_PARAM
    assert type_info.args[0].name == "T"


def test_parse_nested_generic_with_typevar():
    """测试解析嵌套泛型类型中的 TypeVar"""
    # 创建注册表并注册多个 TypeVar
    registry = SymbolRegistry()

    for name in ["K", "V"]:
        template_param = TemplateParam(
            name=name,
            constraint_kind=ConstraintKind.NONE,
            description=f"TypeVar {name}",
        )
        typevar_symbol = Symbol(
            name=name,
            kind=SymbolKind.TYPE_PARAM,
            type_info=TypeInfo(kind=TypeKind.TYPE_PARAM, name=name),
            template_params=[template_param],
            module="test",
        )
        registry._types[name] = typevar_symbol

    # 解析 list[tuple[K, V]]
    type_info = parse_type_with_context("list[tuple[K, V]]", registry=registry)
    assert type_info.kind == TypeKind.GENERIC
    assert type_info.name == "list"

    # 检查嵌套的 tuple[K, V]
    tuple_type = type_info.args[0]
    assert tuple_type.kind == TypeKind.GENERIC
    assert tuple_type.name == "tuple"
    assert len(tuple_type.args) == 2

    # 检查 K 和 V 都被识别为 TYPE_PARAM
    assert tuple_type.args[0].kind == TypeKind.TYPE_PARAM
    assert tuple_type.args[0].name == "K"
    assert tuple_type.args[1].kind == TypeKind.TYPE_PARAM
    assert tuple_type.args[1].name == "V"


def test_parse_mixed_types():
    """测试解析混合类型（基础类型 + TypeVar）"""
    # 创建注册表并注册 TypeVar
    registry = SymbolRegistry()

    template_param = TemplateParam(
        name="T",
        constraint_kind=ConstraintKind.UNION,
        allowed_types=["int"],
        description="TypeVar with bound",
    )
    typevar_symbol = Symbol(
        name="T",
        kind=SymbolKind.TYPE_PARAM,
        type_info=TypeInfo(kind=TypeKind.TYPE_PARAM, name="T", template_bound="int"),
        template_params=[template_param],
        module="test",
    )
    registry._types["T"] = typevar_symbol

    # 解析 dict[str, T]
    type_info = parse_type_with_context("dict[str, T]", registry=registry)
    assert type_info.kind == TypeKind.GENERIC
    assert type_info.name == "dict"
    assert len(type_info.args) == 2

    # str 应该是 PRIMITIVE
    assert type_info.args[0].kind == TypeKind.PRIMITIVE
    assert type_info.args[0].name == "str"

    # T 应该是 TYPE_PARAM
    assert type_info.args[1].kind == TypeKind.TYPE_PARAM
    assert type_info.args[1].name == "T"
    assert type_info.args[1].template_bound == "int"


def test_parse_complex_nested_types():
    """测试解析复杂嵌套类型"""
    # 测试多层嵌套的泛型类型
    test_cases = [
        ("int", TypeKind.PRIMITIVE),
        ("str", TypeKind.PRIMITIVE),
        ("list[int]", TypeKind.GENERIC),
        ("dict[str, int]", TypeKind.GENERIC),
        ("tuple[int, str, bool]", TypeKind.GENERIC),
        ("list[dict[str, int]]", TypeKind.GENERIC),
    ]

    for type_str, expected_kind in test_cases:
        result = parse_type_with_context(type_str)
        assert result.kind == expected_kind, f"Failed for {type_str}"

        # 验证泛型类型的名称正确
        if expected_kind == TypeKind.GENERIC:
            base_name = type_str.split("[")[0]
            assert result.name == base_name
